除了一對多的關聯方式以外,資料和資料間也有可能是多對多的關聯方式。
比方說常見的用戶標籤(tag) 系統,就是一種多對多的關聯:每個標籤可能對應多個用戶,而每個用戶也可能被標記上多個不同標籤。
要怎麼設計這樣的關聯呢?我們一起來看看
多對多關係的處理方式,比較建議的做法是設計一個中間表,每筆資料紀錄
比方說,如果我們的資料是
user | 
tag | 
|---|---|
| Alice | admin, registered, author | 
| Bob | customer, unregistered | 
| Carol | customer, registered, reader | 
那我們的資料表內容可能會是
|user|
|---|---|
|id|name|
|1|Alice|
|2|Bob|
|3|Carol|
|tag|
|---|---|
|id|name|
|1|admin|
|2|registered|
|3|author|
|4|customer|
|5|unregistered|
|6|reader|
|user_tag|
|---|---|
|user_id|tag_id|
|1|1|
|1|2|
|1|3|
|2|4|
|2|5|
|3|4|
|3|2|
|3|6|
假設我們需要的用戶標籤系統,tag 資料表和 DAO 物件如下
object Tags : IntIdTable() {  
    val name = varchar("name", 50)  
}  
  
class Tag(id: EntityID<Int>) : IntEntity(id) {  
    companion object : IntEntityClass<Tag>(Tags)  
    var name by Tags.name  
}
我們定義中間表 user_tag 如下
object UserTag : IntIdTable() {  
    val user = reference("user", Users)  
    val tag = reference("tag", Tags)  
}
利用 via 這個內綴,我們讓 user 和 tag 物件與 UserTag 資料表進行關聯
class Tag(id: EntityID<Int>) : IntEntity(id) {  
    companion object : IntEntityClass<Tag>(Tags)  
    var name by Tags.name  
 	var users by User via UsersTags  
}
class User(id: EntityID<Int>) : IntEntity(id) {  
    companion object : IntEntityClass<User>(Users)  
    var name by Users.name  
 	var tags by Tag via UsersTags  
}
並且定義 user 和 tag 內容
SchemaUtils.create(Users)  
SchemaUtils.create(Tags)  
val alice = User.new {  
 	name = "Alice"  
}  
val bob = User.new {  
 	name = "Bob"  
}  
val carol = User.new {  
 	name = "Carol"  
}  
val admin = Tag.new {  
 	name = "admin"  
}  
val registered = Tag.new {  
 	name = "registered"  
}  
val author = Tag.new {  
 	name = "author"  
}  
val customer = Tag.new {  
 	name = "customer"  
}  
val unregistered = Tag.new {  
 	name = "unregistered"  
}  
val reader = Tag.new {  
 	name = "reader"  
}
定義完成之後,我們就可以以 DAO  的方式,進行 user 和 tag 的關聯了
alice.tags = SizedCollection(listOf(admin, registered, author))  
bob.tags = SizedCollection(listOf(customer, unregistered))  
carol.tags = SizedCollection(listOf(customer, registered, reader))
定義完成之後,我們可以透過 user 來找到所有對應的 tag
carol.tags.forEach { println("tag: ${it.name}") }
上面這段程式碼會印出
tag: customer
tag: registered
tag: reader
我們也可以透過 tag 來找到對應的 user
registered.users.forEach { println("user: ${it.name}") }
上面這段程式碼會印出
user: Alice
user: Carol
透過 DAO 的方式,以物件的思維,來實作多對多的資料關聯語法,個人認為比起透過 query 關聯的方式來說,更加直觀並且好操作許多。